<template>
  <view class="scroll-picker-container">
    <view class="indicator"></view>
    <scroll-view
      scroll-y="true"
      class="scroll-picker-box"
      :scroll-top="scrollTop"
      @scroll="throttledScroll"
      @scrollend="handleScrollEnd"
      ref="pickerRef"
      scroll-with-animation="true"
      :style="{ height: visibleItemCount * itemHeight + 'px' }"
    >
      <view
        class="scroll-picker-item"
        v-for="(item, index) of renderColumns"
        :key="index"
        :class="{ current: item === selectedValue }"
        :style="{ height: itemHeight + 'px', lineHeight: itemHeight + 'px' }"
        @click="handleItemClick(item)"
      >
        {{ item }}
      </view>
    </scroll-view>
  </view>
</template>

<script setup>
import { computed, onMounted, ref, watch } from 'vue'
import { throttle } from 'lodash'

const DEFAULT_ITEM_HEIGHT = 40 // 默认选项高度
const EMPTY_PLACEHOLDER = ''

const scrollTop = ref(0) // 滚动高度
const selectedValue = ref('') // 当前选中的值
const pickerRef = ref(null) // scroll-view 的 ref
const itemHeight = ref(DEFAULT_ITEM_HEIGHT) // 选项高度
const isScrolling = ref(false) // 标记是否正在滚动

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
  options: {
    type: Array,
    default: () => [],
  },
  visibleItemCount: {
    type: Number,
    default: 5,
    validator: (value) => value % 2 === 1 && value >= 3, // 必须是奇数且大于等于 3
  },
})

const emit = defineEmits(['update:modelValue', 'change'])

onMounted(() => {
  // 动态获取 itemHeight (在 DOM 渲染后)
  setTimeout(() => {
    const firstItem = document.querySelector('.scroll-picker-item')
    if (firstItem) {
      itemHeight.value = firstItem.offsetHeight || DEFAULT_ITEM_HEIGHT
    }
    setInitialScroll()
  }, 0)
})

// 渲染带上下空白的列
const renderColumns = computed(() => {
  if (props.options.length) {
    const emptyCount = Math.floor(props.visibleItemCount / 2)
    const emptyArray = Array(emptyCount).fill(EMPTY_PLACEHOLDER)
    return [...emptyArray, ...props.options, ...emptyArray]
  } else {
    return []
  }
})

// 监听 options 变化，重置选中值和滚动位置
watch(
  () => props.options,
  () => {
    if (props.options.length > 0) {
      selectedValue.value = props.options[0]
      setInitialScroll()
    } else {
      selectedValue.value = ''
      scrollTop.value = 0
    }
  },
  { deep: true },
)

// 监听 modelValue 变化，同步组件内部的 selectedValue
watch(
  () => props.modelValue,
  (newValue) => {
    if (newValue !== selectedValue.value && props.options.includes(newValue)) {
      selectedValue.value = newValue
      scrollToValue(newValue)
    } else if (props.options.length > 0 && !props.modelValue) {
      selectedValue.value = props.options[0]
      setInitialScroll()
    }
  },
  { immediate: true },
)

// 监听内部 selectedValue 变化，触发 emit
watch(
  () => selectedValue.value,
  (newValue) => {
    emit('update:modelValue', newValue)
    emit('change', newValue)
  },
)

const setInitialScroll = () => {
  if (props.options.length > 0 && itemHeight.value > 0) {
    const initialIndex = props.options.indexOf(selectedValue.value)
    if (initialIndex !== -1) {
      scrollTop.value = (initialIndex + Math.floor(props.visibleItemCount / 2)) * itemHeight.value
    } else {
      scrollTop.value = Math.floor(props.visibleItemCount / 2) * itemHeight.value // Default to the first item
      if (props.options.length > 0) {
        selectedValue.value = props.options[0]
      }
    }
  }
}

const scrollToValue = (value) => {
  if (props.options.length > 0 && itemHeight.value > 0) {
    const index = props.options.indexOf(value)
    if (index !== -1) {
      scrollTop.value = (index + Math.floor(props.visibleItemCount / 2)) * itemHeight.value
    }
  }
}

const handleScroll = (ev) => {
  isScrolling.value = true
  if (itemHeight.value > 0 && props.options.length > 0) {
    const scroll = ev.detail.scrollTop
    const index = Math.round(scroll / itemHeight.value) - Math.floor(props.visibleItemCount / 2)
    if (props.options[index] !== undefined && props.options[index] !== selectedValue.value) {
      selectedValue.value = props.options[index]
    }
  }
}

const throttledScroll = throttle(handleScroll, 50)

const handleScrollEnd = (ev) => {
  isScrolling.value = false
  const scroll = ev.detail.scrollTop
  if (itemHeight.value > 0 && props.options.length > 0) {
    const index = Math.round(scroll / itemHeight.value)
    const targetIndex = Math.max(
      0,
      Math.min(props.options.length + Math.floor(props.visibleItemCount / 2) - 1, index),
    )
    scrollTop.value = targetIndex * itemHeight.value
    selectedValue.value = renderColumns.value[targetIndex]
  }
}

const handleItemClick = (item) => {
  if (!isScrolling.value && item !== EMPTY_PLACEHOLDER && selectedValue.value !== item) {
    selectedValue.value = item
    scrollToValue(item)
  }
}
</script>

<style scoped lang="scss">
.scroll-picker-container {
  position: relative;
  width: 100%;
  overflow: hidden;

  .indicator {
    position: absolute;
    top: calc(50% - 0.5 * v-bind(itemHeight));
    left: 0;
    width: 100%;
    height: v-bind(itemHeight);
    border-top: 1px solid #ccc;
    border-bottom: 1px solid #ccc;
    box-sizing: border-box;
    pointer-events: none;
  }

  .scroll-picker-box {
    position: relative;
    width: 100%;
    overflow-y: scroll;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    margin: 0;
    padding: 0;

    &::-webkit-scrollbar {
      display: none;
    }

    .scroll-picker-item {
      display: flex;
      align-items: center;
      justify-content: center;
      transition: all 0.2s;
      cursor: pointer;
      user-select: none; /* 防止文本被选中 */
      color: #333;

      &.current {
        font-weight: 600;
        font-size: 1.2em;
        color: darkblue;
      }

      &:not(.current) {
        color: #999;
      }
    }
  }
}
</style>
